<template>
  <div class="code-to-flow">
    <div class="editor-container">
      <MonacoEditor
        :code="code"
        :language="language"
        :theme="theme"
        :options="editorOptions"
        @codeChange="onCodeChange"
      />
    </div>
    <div class="flow-chart-container">
      <VueFlow
        :nodes="elements.nodes"
        :edges="elements.edges"
        :class="{ dark }"
        class="basic-flow"
        :default-viewport="{ zoom: 1.5 }"
        :min-zoom="0.2"
        :max-zoom="4"
      >
        <Background pattern-color="#aaa" :gap="16" />

        <MiniMap />

        <Controls position="top-left">
          <ControlButton title="Reset Transform" @click="resetTransform">
            <Icon name="reset" />
          </ControlButton>

          <ControlButton title="Shuffle Node Positions" @click="updatePos">
            <Icon name="update" />
          </ControlButton>

          <ControlButton title="Toggle Dark Mode" @click="toggleDarkMode">
            <Icon v-if="dark" name="sun" />
            <Icon v-else name="moon" />
          </ControlButton>

          <ControlButton title="Log `toObject`" @click="logToObject">
            <Icon name="log" />
          </ControlButton>
        </Controls>
      </VueFlow>
      <!-- <div v-else class="placeholder">请在左侧输入代码以生成流程图</div> -->
    </div>
  </div>
</template>

<script>
import { ref, onMounted, onUnmounted } from 'vue';
import MonacoEditor from 'vue-monaco-editor';
import { VueFlow, useVueFlow } from '@vue-flow/core'
import { Background } from '@vue-flow/background'
import { ControlButton, Controls } from '@vue-flow/controls'
import { MiniMap } from '@vue-flow/minimap'
import { initialEdges, initialNodes } from './initial-elements.js'
import Icon from './VueFlowIcon.vue'
import { parseCodeToFlow } from '../js/parser.js';

export default {
  name: 'CodeToFlow',
  components: {
    VueFlow,
    MiniMap,
    Controls,
    Background,
    MonacoEditor, // 引入 MonacoEditor 组件
  },
  setup() {
    const code = ref(''); // 编辑器中的代码
    const language = ref('cpp'); // 编辑器的语言模式
    const theme = ref('vs-dark'); // 编辑器的主题
    const elements = ref([]); // 流程图的元素
    const defaultEdgeOptions = ref({
      animated: true,
      style: { stroke: '#f6f6f6' },
    });

    // 编辑器的配置选项
    const editorOptions = ref({
      selectOnLineNumbers: true, // 点击行号时选择整行
      automaticLayout: false, // 关闭自动布局
      minimap: { enabled: false }, // 关闭小地图
      scrollBeyondLastLine: false, // 禁止滚动超过最后一行
      readOnly: false, // 设置为可编辑
      lineNumbers: 'on', // 显示行号
      tabSize: 4, // Tab 大小
      fontSize: 14, // 字体大小
      wordWrap: 'on', // 自动换行
      suggestOnTriggerCharacters: false, // 禁用触发字符时的自动补全
      acceptSuggestionOnEnter: 'off', // 禁用 Enter 键接受建议
      quickSuggestions: false, // 禁用快速建议
      parameterHints: false, // 禁用参数提示
      lightbulb: { enabled: false }, // 禁用代码操作提示（如修复建议）
      glyphMargin: false, // 禁用左侧边栏的错误提示线
      rulers: [], // 移除标尺
      showFoldingControls: 'never', // 禁用折叠控件
      folding: false, // 禁用代码折叠
      inlineSuggest: false, // 禁用内联建议
      formatOnPaste: false, // 禁用粘贴时的格式化
      formatOnType: false, // 禁用输入时的格式化
      autoIndent: 'none', // 禁用自动缩进
      renderValidationDecorations: 'off', // 禁用错误提示装饰
      hover: { enabled: false }, // 禁用悬停提示
    });

    /**
     * `useVueFlow` provides:
     * 1. a set of methods to interact with the VueFlow instance (like `fitView`, `setViewport`, `addEdges`, etc)
     * 2. a set of event-hooks to listen to VueFlow events (like `onInit`, `onNodeDragStop`, `onConnect`, etc)
     * 3. the internal state of the VueFlow instance (like `nodes`, `edges`, `viewport`, etc)
     */
    const { onInit, onNodeDragStop, onConnect, addEdges, setViewport, toObject } = useVueFlow()

    const nodes = ref(initialNodes)

    const edges = ref(initialEdges)

    // our dark mode toggle flag
    const dark = ref(false)

    /**
     * This is a Vue Flow event-hook which can be listened to from anywhere you call the composable, instead of only on the main component
     * Any event that is available as `@event-name` on the VueFlow component is also available as `onEventName` on the composable and vice versa
     *
     * onInit is called when the VueFlow viewport is initialized
     */
    onInit((vueFlowInstance) => {
      // instance is the same as the return of `useVueFlow`
      vueFlowInstance.fitView()
    })

    /**
     * onNodeDragStop is called when a node is done being dragged
     *
     * Node drag events provide you with:
     * 1. the event object
     * 2. the nodes array (if multiple nodes are dragged)
     * 3. the node that initiated the drag
     * 4. any intersections with other nodes
     */
    onNodeDragStop(({ event, nodes, node }) => {
      console.log('Node Drag Stop', { event, nodes, node })
    })

    /**
     * onConnect is called when a new connection is created.
     *
     * You can add additional properties to your new edge (like a type or label) or block the creation altogether by not calling `addEdges`
     */
    onConnect((connection) => {
      addEdges(connection)
    })

    // /**
    //  * To update a node or multiple nodes, you can
    //  * 1. Mutate the node objects *if* you're using `v-model`
    //  * 2. Use the `updateNode` method (from `useVueFlow`) to update the node(s)
    //  * 3. Create a new array of nodes and pass it to the `nodes` ref
    //  */
    // function updatePos() {
    //   nodes.value = nodes.value.map((node) => {
    //     return {
    //       ...node,
    //       position: {
    //         x: Math.random() * 400,
    //         y: Math.random() * 400,
    //       },
    //     }
    //   })
    // }

    // /**
    //  * toObject transforms your current graph data to an easily persist-able object
    //  */
    // function logToObject() {
    //   console.log(toObject())
    // }

    // /**
    //  * Resets the current viewport transformation (zoom & pan)
    //  */
    // function resetTransform() {
    //   setViewport({ x: 0, y: 0, zoom: 1 })
    // }

    // function toggleDarkMode() {
    //   dark.value = !dark.value
    // }
    // 当代码发生变化时，重新生成流程图
    function onCodeChange(newCode) {
      code.value = newCode.getValue();
      // console.log(parseCodeToFlow("int i = 0;\nwhile (i < 5) \n{\ni++;\n}\n"));
      // console.log(parseCodeToFlow(newCode.getValue()));
      elements.value = parseCodeToFlow(newCode.getValue())[0];
    }

    // 在组件挂载后初始化编辑器
    onMounted(() => {
      // 如果需要在挂载时执行额外的初始化逻辑，可以在这里添加
    });

    // 在组件卸载时清理资源，避免内存泄漏
    onUnmounted(() => {
      // 如果需要在卸载时执行清理逻辑，可以在这里添加
    });

    return {
      code,
      language,
      theme,
      editorOptions,
      elements,
      nodes,
      edges,
      defaultEdgeOptions,
      onCodeChange,
    };
  },
};
</script>

<style scoped>
.code-to-flow {
  display: flex;
  height: 100vh; /* 确保整个容器占据整个视口高度 */
}

.editor-container {
  flex: 1; /* 让编辑器容器占据左侧一半的空间 */
  border-right: 1px solid #ccc;
  text-align: left;
  height: 100vh; /* 确保编辑器容器高度为 100% */
  position: relative; /* 确保子元素可以相对于容器定位 */
  overflow: hidden; /* 防止内容溢出 */
}

.flow-chart-container {
  flex: 1; /* 让流程图容器占据右侧一半的空间 */
  position: relative;
  height: 100vh; /* 确保流程图容器高度为 100% */
  overflow: hidden; /* 防止内容溢出 */
}

.placeholder {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: #999;
  font-size: 16px;
}
</style>